package com.tjs.lucky.infrastructure.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;

/**
 * @author TJS
 * @Description
 * @create 2023/7/15 22:09
 */
@SuppressWarnings("ConstantConditions")
@Component
@Slf4j
public class OptimisticLock {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final DefaultRedisScript<Boolean> DEDUCT_AWARD_STOCK_SCRIPT;

    private static final DefaultRedisScript<Boolean> DEDUCT_ACTIVITY_STOCK_SCRIPT;

    static {
        DEDUCT_AWARD_STOCK_SCRIPT = new DefaultRedisScript<>();
        DEDUCT_AWARD_STOCK_SCRIPT.setLocation(new ClassPathResource("deductAwardStock.lua"));
        DEDUCT_AWARD_STOCK_SCRIPT.setResultType(Boolean.class);

        DEDUCT_ACTIVITY_STOCK_SCRIPT = new DefaultRedisScript<>();
        DEDUCT_ACTIVITY_STOCK_SCRIPT.setLocation(new ClassPathResource("deductActivityStock.lua"));
        DEDUCT_ACTIVITY_STOCK_SCRIPT.setResultType(Boolean.class);
    }

    /**
     * 扣奖品库存
     *
     * @param key
     * @param field
     * @return
     */
    public boolean deductAwardStock(String key, String field) {
        // 必须在内部try catch，因为如果发送异常，被外部try 捕捉到，执行库存回退操作，会导致库存没扣成，反倒增加
        try {
            return stringRedisTemplate.execute(DEDUCT_AWARD_STOCK_SCRIPT, Arrays.asList(key, field));
        } catch (Exception e) {
            log.error("执行扣奖品库存执行错误");
        }
        return false;
    }

    /**
     * 扣活动库存
     *
     * @param key
     * @return
     */
    public boolean deductActivityStock(String key) {
        try {
            return stringRedisTemplate.execute(DEDUCT_ACTIVITY_STOCK_SCRIPT, Collections.singletonList(key));
        } catch (Exception e) {
            log.error("扣除库存脚本执行错误...");
        }
        return false;
    }
}
